package com.example.gezihua.myapplication.pull;

import android.animation.ValueAnimator;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.ViewConfiguration;
import android.view.animation.DecelerateInterpolator;
import android.widget.RelativeLayout;

import com.example.gezihua.myapplication.R;

import java.lang.ref.WeakReference;

/**
 * Created by gezihua on 16-12-20.
 */

public class PullToRefresh extends RelativeLayout {
    private boolean mIsBeingDragged;
    private float mTouchSlop;
    private float mStartY;
    private float mLastMottionY;
    private ValueAnimator mResetAnimation;


    public void setmRefreshView(IPullView mRefreshView) {
        this.mRefreshView = mRefreshView;
    }

    private IPullView mRefreshView;

    public void setHeaderView(IHeaderView headerView) {
        mHeaderView = headerView;
    }

    private IHeaderView mHeaderView;


    public PullToRefresh(Context context) {
        super(context);
        init();
    }

    private void init() {
        ViewConfiguration config = ViewConfiguration.get(getContext());
        mTouchSlop = config.getScaledTouchSlop();
        int dimensionPixelOffset = getResources().getDimensionPixelOffset(R.dimen.pull_to_refresh_max);
        if (dimensionPixelOffset < MAX_PULL) {
            MAX_PULL = dimensionPixelOffset;
        }
    }

    public PullToRefresh(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public PullToRefresh(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        //能相应第一个应该是Down事件
        // 对于能滚动View的View来说，这个时候应该已经滚动到最上边
        if (mRefreshView == null || !mRefreshView.canScroll()) {
            Log.e("suj", "can scroll" + mRefreshView.canScroll());
            mIsBeingDragged = false;
            return super.onInterceptTouchEvent(ev);
        }
        int action = ev.getAction();
        Log.e("suj", "onInterceptTouchEvent" + ev.toString());
        switch (action) {
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                if (mIsBeingDragged) {
                    return true;
                }
                break;
            }

            // 这里应该返回false ,别问我为什么
            //如果子布局还要处理事件，这里一定要返回false
            //真正拦截不下发的地方应该在 move 事件
            case MotionEvent.ACTION_DOWN: {
                return startDragging(ev);
            }
            case MotionEvent.ACTION_MOVE: {
                return onDragging(ev);
            }
        }

        return super.onInterceptTouchEvent(ev);
    }

    private boolean onDragging(MotionEvent ev) {
        mLastMottionY = ev.getY();
        if (mLastMottionY < mStartY) {
            mIsBeingDragged = false;
            return false;
        }
        mIsBeingDragged = true;
        boolean dragging = Math.abs(mLastMottionY - mStartY) >= mTouchSlop;
        //Log.e("suj","can dragging"+dragging);
        return dragging;
    }

    private boolean startDragging(MotionEvent ev) {
        mStartY = ev.getY();
        mIsBeingDragged = true;
        return false;
    }

    private boolean showHeaderView() {
        if (mHeaderView == null) {
            return false;
        }
        return mHeaderView.canRefresh();
    }

    private static class H extends Handler {
        WeakReference<PullToRefresh> pullToRefreshRef;

        public H(PullToRefresh refresh) {
            pullToRefreshRef = new WeakReference<PullToRefresh>(refresh);
        }

        @Override
        public void dispatchMessage(Message msg) {
            super.dispatchMessage(msg);
            if (msg.what != MSG_END_DRAGGING) {
                return;
            }
            PullToRefresh pullToRefresh = pullToRefreshRef.get();
            if (pullToRefresh == null) {
                return;
            }
            pullToRefresh.reset();
        }
    }

    private final static int MSG_END_DRAGGING = 1;

    private H mH;

    private Message generateDraggingMsg(int msg) {
        Message obtain = Message.obtain();
        obtain.what = msg;
        return obtain;
    }


    private void handleEndDragging(MotionEvent ev) {
        mIsBeingDragged = false;
        mLastMottionY = 0;
        mStartY = 0;
        // 为了解决不能连续刷新的问题，应该把以前的动画以及刷新动画停止，并且重置状态
        removeDelayEndDragging();
        endResetAnimation();
        // then we can do some refresh animator;
        // if the header is not show ,we can  do animation immediately
        if (showHeaderView()) {
            if (mH == null) {
                mH = new H(this);
            }
            mH.sendMessageDelayed(generateDraggingMsg(MSG_END_DRAGGING), 350);
            // then we can start refresh animation
            mHeaderView.showRefresh();
        } else {
            reset();
        }


    }

    private void removeDelayEndDragging() {
        if (mH == null) {
            return;
        }
        mH.removeMessages(MSG_END_DRAGGING);
    }

    private void endResetAnimation(){
        if (mResetAnimation==null){
            return;
        }
        if (mResetAnimation.isRunning()){
            mResetAnimation.cancel();
        }
    }
    private void endHeaderAnimation(){
        if (mHeaderView==null){
            return;
        }
        mHeaderView.cancelRefresh();
    }



    // when destroy we must remove the delayed msg
    @Override
    protected void onDetachedFromWindow() {
        super.onDetachedFromWindow();
        removeDelayEndDragging();
    }

    private void reset() {
        mResetAnimation = ValueAnimator.ofFloat(mRefreshView.getPullTransY(), 0);
        mResetAnimation.setDuration(350);
        mResetAnimation.setRepeatMode(ValueAnimator.RESTART);
        mResetAnimation.setInterpolator(new DecelerateInterpolator());
        mResetAnimation.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                float animatedValue = (float) animation.getAnimatedValue();
                mRefreshView.setPullTransY((int) animatedValue);
            }
        });
        mResetAnimation.start();
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        Log.e("suj", "onTouchEvent" + event.toString());
        if (mIsBeingDragged) {
            int action = event.getAction();
            //Log.e("suj","onTouchEvent"+event.toString());
            switch (action) {
                case MotionEvent.ACTION_CANCEL:
                case MotionEvent.ACTION_UP: {
                    handleEndDragging(event);
                    break;
                }
                case MotionEvent.ACTION_MOVE: {
                    return handleDragging(event);
                }
                case MotionEvent.ACTION_DOWN: {
                    break;
                }
            }
            return true;

        }
        return super.onTouchEvent(event);
    }

    private int MAX_PULL = 300;

    private boolean handleDragging(MotionEvent event) {
        if (mRefreshView == null) {
            return false;
        }
        mLastMottionY = event.getY();
        if (mLastMottionY < mStartY) {
            return false;
        }
        int lastTransY = mRefreshView.getPullTransY();
        float v = mLastMottionY - mStartY;
        //Log.e("suj","mLastMottionY"+mLastMottionY+"startY"+mStartY);
        int pull = (lastTransY + v) / 2 > MAX_PULL ? MAX_PULL : (int) (lastTransY + v) / 2;
        mRefreshView.setPullTransY(pull);
        return true;

    }
}
